package statemodel.entity;

import lombok.Data;
import statemodel.base.BaseState;
import statemodel.impl.*;

import java.io.Serializable;

/**
 * 状态模式的实现:
 * 新的糖果机  (状态机)
 * 启用单例模式
 * 可能不止四个状态
 * 每个状态都是一个实例引用
 *
 * @author yaojianfeng
 */
@Data
public class NewGumballMachine implements Serializable {
    private static final long serialVersionUID = 984562316L;
    /**
     * 地理位置
     */
    private String location;
    private volatile static NewGumballMachine newGumballMachine;
    /**
     * 这就是那四个状态
     * 它们符合万能糖果公司的状态图
     * 直接初始化
     */
    private BaseState hasQuarterState = new HasQuarterStateImpl(this);
    private BaseState noQuarterState = new NoQuarterStateImpl(this);
    private BaseState soldOutState = new SoldOutStateImpl(this);
    private BaseState soldState = new SoldStateImpl(this);
    private BaseState winnerState = new WinnerStateImpl(this);
    private BaseState headState = new HeadStateImpl(this);

    /**
     * 这个实例变量跟踪当前状态,一开始被设置为"糖果售罄"
     */
    BaseState state = headState;
    /**
     * 这个实例变量 用来追踪机器内的糖果数目
     * 初始值为0
     */
    int count = 0;

    /**
     * 构造器需要初始化糖果库存量当做参数
     * 如果库存不为0 机器就会进入"没有25分钱"的状态 ,也就是说它等着别人投入25分钱
     * 如果糖果数目为0的话,机器就会保持在"糖果售罄"的状态
     * 初始化糖果机的时候 每一种状态也都创建一个状态实例
     *
     * @param numberGumballs 糖果数目
     */
    private NewGumballMachine(int numberGumballs) {
        this.count = numberGumballs;
        //如果糖果 数目超过零颗 我们就把状态设置为noQuarterState;
        if (count > 0) {
            state = noQuarterState;
        }
    }

    private NewGumballMachine() {
        //如果糖果 数目超过零颗 我们就把状态设置为noQuarterState;
        if (count > 0) {
            state = noQuarterState;
        }
    }

    public static NewGumballMachine getInstance() {
        if (newGumballMachine == null) {
            synchronized (NewGumballMachine.class) {
                if (newGumballMachine == null) {
                    newGumballMachine = new NewGumballMachine();
                }
            }
            newGumballMachine = new NewGumballMachine();
        }

        return newGumballMachine;
    }

    /**
     * 实现投掷25分硬币的方法 以及其状态转换
     * 将糖果机的行为  委托给状态对象
     * 由当前持有的状态对象来决定糖果机的行为
     */
    public void insertQuarter() {
        state.insertQuarter();
    }

    /**
     * 退币
     */
    public void ejectQuarter() {
        state.ejectQuarter();
    }

    /**
     * 转动曲柄
     */
    public void turnCrank() {
        state.turnCrank();
        /**
         * 转动曲柄之后的关联行为
         * 这是一个内部的动作,用户不可以直接要求机器发放糖果
         * todo 其实这个也可以在状态对象的turnCrank方法中关联实现 在这儿就不用重复调用了
         */
        state.dispense();
    }

    /**
     * 释放糖果的辅助方法
     * 释放一颗 将糖果数量减少1
     */
    public void releaseBall() {

        if (count > 0) {
            System.out.println("糖果机释放一颗糖果!");
            count = count - 1;
        } else {
            System.out.println("老婆大人快来呀,快点给我装点糖果ლ(°◕‵ƹ′◕ლ)");
            System.out.println("再不来装糖果,我就要被拆掉啦ヽ(*。>Д<)o゜");
        }
    }

    /**
     * 重装糖果的方法  其实可以由setCount()方法替代
     *
     * @param count 重装的数目
     */
    public void refill(int count) {
        this.count = count;
        state = noQuarterState;
    }


}
